package com.zlyx.easy.socket.core;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.util.Iterator;

import com.zlyx.easy.core.utils.ObjectUtils;
import com.zlyx.easy.core.utils.StringUtils;
import com.zlyx.easy.socket.core.supports.AbstractMsgHandlerFactory;
import com.zlyx.easy.socket.interfaces.IMsgHandler;

/**
 * NIO方式处理UDP消息工厂
 * 
 * @author 赵光
 * @Description: NIO方式处理UDP消息工厂
 * @date 2018年11月14日
 */
public class NioUdpMsgHandlerFactory extends AbstractMsgHandlerFactory {

	DatagramChannel datagramChannel;
	DatagramSocket datagramSocket;
	Selector selector;

	public NioUdpMsgHandlerFactory(int port, float size, IMsgHandler<?> handler) throws Exception {
		super(port, size, handler);
		datagramChannel = DatagramChannel.open();
		datagramChannel.configureBlocking(false);
		datagramSocket = datagramChannel.socket();
		datagramSocket.setReceiveBufferSize(this.BLOCK);
		datagramSocket.bind(new InetSocketAddress(this.PORT));
		selector = Selector.open();
		datagramChannel.register(selector, SelectionKey.OP_READ);
	}

	@Override
	public boolean doBlock() throws Exception {
		selector.select();
		Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
		while (iterator.hasNext()) {
			SelectionKey selectionKey = iterator.next();
			handleKey(selectionKey);
			iterator.remove();
		}
		return true;
	}

	private void handleKey(SelectionKey selectionKey) throws Exception {
		ByteBuffer byteBuffer = ByteBuffer.allocate(100);
		if (selectionKey.isReadable()) {
			datagramChannel = (DatagramChannel) selectionKey.channel();
			byteBuffer.clear();
			SocketAddress socketAddress = datagramChannel.receive(byteBuffer);
			byteBuffer.flip();
			CharBuffer charBuffer = Charset.defaultCharset().decode(byteBuffer);
			if (StringUtils.isNotEmpty(charBuffer.toString())) {
				byte[] res = doHandler(charBuffer.toString());
				if (ObjectUtils.isNotEmpty(res)) {
					ByteBuffer buffer = Charset.defaultCharset().encode(new String(res));
					datagramChannel.send(buffer, socketAddress);
				}
			}
		}
	}

	@Override
	public void closeServer() throws Exception {
		if (datagramChannel != null) {
			datagramChannel.close();
		}
		if (datagramSocket != null) {
			datagramSocket.close();
		}
		if (selector != null) {
			selector.close();
		}
	}
}
